/*
 * Copyright (c) 2006-2021, JingJia Micro ltd.
 * 
 * License: Apache-2.0
 * 
 * File: table.c
 * Desc: table object
 * 
 * Change Logs:
 * Date             Author                 Notes
 * 2021-07-25       romix                  The first version
 */

#include "common.h"
#include "table.h"

/**
 * @brief create a table
 *
 * @param timer add a timer for table
 * @param hook add a hook function for operate the table
 */
table_t *table_create(char *name)
{
    table_t *table = NULL;

    table = (table_t *)malloc(sizeof(table_t));
    if (NULL == table) {
        fprintf(stderr, "malloc table failed.\n");
        return NULL;
    }

    table->table_header = create_table_entry(NULL); 
    list_init(&(table->table_header->knot));

    strcpy(table->name, name);

    return table;
}

/**
 * @brief delete the table
 *
 * @param table the table object
 */
int32_t table_delete(table_t *table)
{
    struct list_node *node = NULL;
    struct list_node *temp = NULL;
    table_entry_t *entry = NULL;

    table_entry_t *header = table->table_header;

    assert(NULL != table);

    if (NULL != table->table_timer) {
        (table->table_timer->stop)(table->table_timer);
        sleep(0.1);
        delete_timer(table->table_timer);
        table->table_timer = NULL;
    }

    list_for_each_safe(node, temp, &(header->knot)) {
        list_remove(node);
        entry = container_of(node, table_entry_t, knot);
        free(entry->data);
        entry->data = NULL;
        free(entry);
        entry = NULL;
    }     

    if (header->data)
        free(header->data);

    free(header);
    free(table);

    return OKAY;
}

/**
 * @brief delete the table all entry
 *
 * @param table the table entry object
 */
int32_t table_delete_entry(table_t *table)
{
    struct list_node *node = NULL;
    struct list_node *temp = NULL;
    table_entry_t *entry = NULL;

    table_entry_t *header = table->table_header;

    assert(NULL != table);

    list_for_each_safe(node, temp, &(header->knot)) {
        list_remove(node);
        entry = container_of(node, table_entry_t, knot);
        free(entry->data);
        entry->data = NULL;
        free(entry);
        entry = NULL;
    }     

    if (header->data) {
        free(header->data);
        header->data = NULL;
    }

    return OKAY;
}

/**
 * @brief Init table and add first entry
 *
 * @param table the table object
 * @param entry add entry
 * @param timer the table object
 * @param hook add entry
 */
int32_t table_init(table_t *table, gp_timer_t *timer, hook_t hook)
{
    assert(NULL != table);

    table->table_timer = timer; 
    table->table_hook = hook;

    return OKAY;
}

/**
 * @brief insert a entry to the before table
 *
 * @param table target table 
 * @param entry add a entry for table
 */
void table_insert_before(table_t *table, table_entry_t *entry)
{
    table_entry_t *header = table->table_header;
    list_insert_before(&header->knot, &entry->knot);
}

/**
 * @brief insert a entry to the before table
 *
 * @param table target table 
 * @param entry add a entry for table
 */
void table_insert_after(table_t *table, table_entry_t *entry)
{
    table_entry_t *header = table->table_header;
    list_insert_after(&header->knot, &entry->knot);
}

/**
 * @brief table remove entry
 *
 * @param entry add a entry for table
 */
void table_remove_entry(table_entry_t *entry)
{
    list_remove(&entry->knot);
    free(entry->data);
    free(entry);
    entry = NULL;
}

/**
 * @brief checkt table is empty
 *
 * @param table target table 
 */
bool table_isempty(table_t *table)
{
    if (NULL == table->table_header) {
        return true;
    } else {
        return false;
    }
}

/**
 * @brief insert a entry to the before table
 *
 * @param table target table 
 * 
 * @return table list len
 */
int32_t table_len(table_t *table)
{
    assert(NULL != table->table_header);

    table_entry_t *header = table->table_header;         
    return list_len(&header->knot);
}

/**
 * @brief insert a entry to the before table
 *
 * @param data the data attach entry
 * 
 * @return table entry
 */
table_entry_t *create_table_entry(void *data)
{
    table_entry_t *entry = NULL;
    
    entry = (table_entry_t *)malloc(sizeof(table_entry_t));
    if (NULL == entry) {
        fprintf(stderr, "malloc table entry failed.\n");

        return NULL;
    } 

    entry->data = data;

    return entry;
}

/**
 * @brief table attach hook 
 *
 * @param table the taget table
 * @param hook the attach hook function
 */
void table_attach_hook(table_t *table, hook_t hook)
{
    table->table_hook = hook;
}